package com.awesome.network.call;

import android.os.Handler;
import android.os.Looper;

import com.awesome.network.callback.Callback;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.internal.bind.TypeAdapters;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;

import java.io.IOException;

import okhttp3.Call;

/**
 * Author: JFangZ
 * Email:janezhang1901@163.com
 * Date: 2021/4/28 9:03
 * Description:Base call for request.
 */
public abstract class AbsCall<T> {
    protected Handler mHandler = new Handler(Looper.getMainLooper());
    protected Call mCall;
    protected Gson mGson = new GsonBuilder()
            .registerTypeAdapterFactory(TypeAdapters.newFactory(int.class, Integer.class, new TypeAdapter<Number>() {
                @Override
                public void write(JsonWriter out, Number value) throws IOException {
                    out.value(value);
                }

                @Override
                public Number read(JsonReader in) throws IOException {
                    if (in.peek() == JsonToken.NULL) {
                        in.nextNull();
                        return null;
                    }
                    try {
                        return in.nextInt();
                    } catch (NumberFormatException e) {
                        in.skipValue();
                        return 0;
                    }
                }
            }))
            .registerTypeAdapterFactory(TypeAdapters.newFactory(long.class, Long.class, new TypeAdapter<Number>() {
                @Override
                public void write(JsonWriter out, Number value) throws IOException {
                    out.value(value);
                }

                @Override
                public Number read(JsonReader in) throws IOException {
                    if (in.peek() == JsonToken.NULL) {
                        in.nextNull();
                        return null;
                    }
                    try {
                        return in.nextLong();
                    } catch (NumberFormatException e) {
                        in.skipValue();
                        return 0L;
                    }
                }
            }))
            .registerTypeAdapterFactory(TypeAdapters.newFactory(float.class, Float.class, new TypeAdapter<Number>() {
                @Override
                public void write(JsonWriter out, Number value) throws IOException {
                    out.value(value);
                }

                @Override
                public Number read(JsonReader in) throws IOException {
                    if (in.peek() == JsonToken.NULL) {
                        in.nextNull();
                        return null;
                    }
                    try {
                        return in.nextDouble();
                    } catch (NumberFormatException e) {
                        in.skipValue();
                        return 0f;
                    }
                }
            }))
            .registerTypeAdapterFactory(TypeAdapters.newFactory(double.class, Double.class, new TypeAdapter<Number>() {
                @Override
                public void write(JsonWriter out, Number value) throws IOException {
                    out.value(value);
                }

                @Override
                public Number read(JsonReader in) throws IOException {
                    if (in.peek() == JsonToken.NULL) {
                        in.nextNull();
                        return null;
                    }
                    try {
                        return in.nextDouble();
                    } catch (NumberFormatException e) {
                        in.skipValue();
                        return 0d;
                    }
                }
            }))
            .create();

    public AbsCall(Call call) {
        this.mCall = call;
    }

    public abstract void enqueue(Callback<T> callback);

    public abstract T execute() throws Exception;

    public abstract <O> TransformCallImpl<T, O> transform(ResponseTransformer<T, O> responseTransformer);

    public void cancel() {
        if (!mCall.isCanceled()) {
            mCall.cancel();
        }
    }
}